use std::{ops::Div, path::Path};

use gset::Getset;
use qiniu_sdk::{
    download::{DownloadManager, EndpointsUrlGenerator, UrlsSigner},
    objects::ObjectsManager,
    upload::{
        apis::{http_client::BucketDomainsQueryer, storage::get_objects::ListedObjectEntry},
        AutoUploader, AutoUploaderObjectParams, UploadManager, UploadTokenSigner,
    },
    upload_token::{credential::Credential, StaticUploadTokenProvider, UploadPolicyBuilder},
};
#[derive(Debug, serde::Serialize, Getset)]
pub struct Entry {
    #[getset(get, name = "get_entry", vis = "pub")]
    #[getset(set_own, name = "entry", vis = "pub")]
    entry: Option<ListedObjectEntry>,
    utc_time: String,
    #[getset(set_own, name = "filesize", vis = "pub")]
    #[getset(set, name = "set_filesize", vis = "pub")]
    filesize: Option<String>,
    #[getset(set_own, name = "filetype", vis = "pub")]
    #[getset(set, name = "set_filetype", vis = "pub")]
    filetype: Option<String>,
    #[getset(set_own, name = "filename", vis = "pub")]
    #[getset(set, name = "set_filename", vis = "pub")]
    filename: Option<String>,
}
impl Entry {
    pub fn new(entry: ListedObjectEntry, utc_time: String) -> Self {
        Self {
            entry: Some(entry),
            utc_time,
            filesize: None,
            filetype: None,
            filename: None,
        }
    }
}
const ACCESS_KEY: &str = "9tttwMZSPnlz22vfabGPJyxg0i8EelagAAJ4-r6c";
const SECRET_KEY: &str = "rPJ8NzXGS3qcVLJEHAf8mDctCVR9DmMEQxDcPj6Y";
const BUCKET_NAME: &str = "result-and-csv";

//DONE: 阻塞上传七牛云
pub fn get_upload_token() -> StaticUploadTokenProvider {
    let credential = Credential::new(ACCESS_KEY, SECRET_KEY);
    //TAG: 使用session每个会话保存一个token
    let upload_policy =
        UploadPolicyBuilder::new_policy_for_bucket(BUCKET_NAME, std::time::Duration::from_secs(10))
            .file_type(qiniu_sdk::upload_token::FileType::Standard)
            .build_token(credential, Default::default());
    upload_policy
}
pub fn upload_to_qiniu(file: impl AsRef<Path>, user_name: &str) -> anyhow::Result<()> {
    let upload_policy = get_upload_token();
    let upload_manager =
        UploadManager::builder(UploadTokenSigner::new_upload_token_provider(upload_policy)).build();

    let upload: AutoUploader = upload_manager.auto_uploader();
    let file_name = file.as_ref().file_name().unwrap().to_str().unwrap();
    let file_extension = file.as_ref().extension().unwrap().to_str().unwrap();
    let params = AutoUploaderObjectParams::builder()
        .object_name(format!("{}/{}/{}", user_name, file_extension, file_name))
        .file_name(file_name)
        .build();
    upload.upload_path(file, params)?;
    Ok(())
}
pub fn object_list(username: String, file_type: String) -> anyhow::Result<Vec<Entry>> {
    let credential = Credential::new(ACCESS_KEY, SECRET_KEY);
    let object_manager = ObjectsManager::builder(credential).build();
    let bucket = object_manager.bucket(BUCKET_NAME);

    let iter = bucket.list().iter();
    let object_entry_array = iter
        .filter_map(|entry| {
            let entry = match entry {
                Ok(item) => item,
                Err(e) => return Some(Err(e.into())),
            };
            if entry.get_key_as_str().contains(&username)
                && entry.get_key_as_str().contains(&file_type)
            {
                let unix_timestamp = entry.get_put_time_as_i64().div(1e7 as i64);
                let utc_time = chrono::DateTime::from_timestamp(unix_timestamp, 0)
                    .unwrap()
                    .format("%Y-%m-%d %H:%M:%S")
                    .to_string();
                Some(Ok(Entry::new(entry, utc_time)))
            } else {
                None
            }
        })
        .collect::<anyhow::Result<Vec<Entry>>>();

    object_entry_array
}
//TODO: 从本地删除用户的预测结果上传的七牛云
pub fn delete_user_predict_result_form_local() {}
//TODO: 异步上传七牛云
pub async fn upload_to_servive(path: String, username: &str) -> anyhow::Result<()> {
    let upload_policy = get_upload_token();
    let upload_manager =
        UploadManager::builder(UploadTokenSigner::new_upload_token_provider(upload_policy)).build();
    let upload: AutoUploader = upload_manager.auto_uploader();
    let file_name = Path::new(&path).file_name().unwrap().to_str().unwrap();
    let file_extension = Path::new(&path).extension().unwrap().to_str().unwrap();
    let params = AutoUploaderObjectParams::builder()
        .object_name(format!("{}/{}/{}", username, file_extension, file_name))
        .file_name(file_name)
        .build();
    upload.async_upload_path(path, params).await?;
    Ok(())
}
pub async fn download_from_qiniu_cloud(object_name: String, path: String) -> anyhow::Result<()> {
    let credential = Credential::new(ACCESS_KEY, SECRET_KEY);
    let download_manager = DownloadManager::new(UrlsSigner::new(
        credential.to_owned(),
        EndpointsUrlGenerator::builder(BucketDomainsQueryer::new().query(credential, BUCKET_NAME))
            .use_https(false)
            .build(),
    ));
    download_manager
        .async_download(object_name)
        .await?
        .async_to_path(path)
        .await?;
    Ok(())
}
#[cfg(test)]
mod qiniu_test {
    use crate::object_list;

    #[test]
    fn get() {
        let username = "root";
        let file_type = "text/csv";
        let res = object_list(username.into(), file_type.into()).unwrap();
        println!("{:#?}", res);
    }
    #[test]
    fn object() {
        let username = "root";
        let file_type = "atext/csv";
        let list = object_list(username.into(), file_type.into()).expect("Error");
        println!("{:#?}", list);
    }
}
